﻿package bakudo.engines.mapEngine.controller.camera {
	import bakudo.engines.mapEngine.events.CameraEvent;
	import bakudo.engines.mapEngine.global.error.MapError;
	import bakudo.engines.mapEngine.model.actors.ModelActor;
	import bakudo.engines.mapEngine.model.WorldModel;
	import flash.display.Scene;	
	import flash.geom.Point;

	import gs.easing.Linear;	
	import gs.TweenLite;	

	import flash.utils.Endian;	

	import bakudo.engines.mapEngine.BakudoMapEngine;	

	import flash.events.TimerEvent;	

	import bakudo.engines.mapEngine.view.scene.Scene2D;	
	import bakudo.engines.mapEngine.view.scene.actors.SceneActor;	

	import flash.utils.Timer;	
	import flash.events.EventDispatcher;

	/**
	 * @author Michał Rabiński
	 * @version 1.0
	 */
	public class Camera2D extends EventDispatcher {

		//::::::::::::::: public vars ::::::::::::::://
		//decyduje o tym czy poruszamy kamera z lekkim opoznieniem czy nie
		public var smooth : Boolean;

		//czy kamera jest zablokowana czy nie
		public var locked : Boolean;

		//obiekt do ktorego centrujemy
		public var lockedObject : ModelActor;
		
		//punkt na, ktory aktualnie wskazuje kamera
		public var cameraPosition : Point = new Point;
		
		private var worldModel : WorldModel;
		
		//::::::::::::::: private vars ::::::::::::::://
		private var timer : Timer = new Timer(10, 0);	

		private var core : BakudoMapEngine;
		
		
		public function Camera2D(core : BakudoMapEngine) {
			init(core);
			worldModel = core.worldModel;
		}

		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// PROTECTED METHODS
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		protected function init(core : BakudoMapEngine) : void {
			this.core = core;		
			timer.addEventListener(TimerEvent.TIMER, onTimerTick, false, 0, true);
			timer.start();			
		}

		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// PUBLIC METHODS
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		
		
		public function update():void {
			onCameraUpdate();
		}
		
		public function setCameraPosition(camX : Number, camY : Number):void {
			if (!worldModel.mapGrid || (worldModel.mapGrid && worldModel.mapGrid.length == 0)) {
				throw new Error(MapError.THERE_IS_NO_MAP);
			}
			var cameraPosition : Point = worldModel.cameraPosition;
			var viewWidth : uint = worldModel.viewWidth;
			var viewHeight : uint = worldModel.viewHeight;
			
			if (smooth) { 
					TweenLite.to(worldModel.cameraPosition, .3, { x : camX, y:camY ,onUpdate : onCameraUpdate} );
			}else {
				// x/y position
				cameraPosition.x = camX// < viewWidth * .5 ? viewWidth * .5 : camX;
				cameraPosition.y = camY// < viewHeight * .5 ? viewHeight* .5 : camY;
				// array index position
				onCameraUpdate();	
			}
			
		}
		
		/**
		 * centruje kamere na obiekcie
		 * @param objectToCenter - obiekt na ktorym centrujemy kamere
		 */
		public function centerToObject(objectToCenter : ModelActor) : void {
			//if(objectToCenter.ready)
			setCameraPosition(objectToCenter.position.x,objectToCenter.position.y);
		}

		/**
		 * centruje kamere na obiekcie caly czas z czestotliwoscia 
		 * interwalu czasowego time'a
		 * @param objectToLock - obiekt na ktorym blokujemy kamere 
		 */
		public function lockToObject(objectToLock : ModelActor) : void {
			lockedObject = objectToLock;
			locked = true;
		}

		/**
		 * wylacza zafixowane centrowanie do obiektu
		 */
		public function releaseLock() : void {
			locked = false;
		}

		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// PRIVATE METHODS
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		
		
		/**
		 * centruje obiekt na obiekt, obliczenia wykonuje wzgledem stage'a
		 * @param objectToCenter - obiekt na ktory centrujemy
		 */
		private function doCenterCamera(objectToCenter : ModelActor) : void {
		
			if (smooth) {
				
			}else { 
				cameraPosition.x = objectToCenter.position.x;
				cameraPosition.y = objectToCenter.position.y;
			}
			onCameraUpdate();
		}

		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		// PRIVATE LISTENERS
		//::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
		private function onTimerTick(event : TimerEvent) : void {
			if(locked) {
				doCenterCamera(lockedObject);
			}
		}
		
		private function onCameraUpdate():void {
			dispatchEvent( new CameraEvent(CameraEvent.CAMERA_UPDATE, false, false));
		}
		
	}
}
